import logging
from contextlib import contextmanager
from sqlalchemy.orm import load_only
from models.schedule import Schedule
import threading
import time
from datetime import datetime, timedelta
from PyQt5.QtCore import QMetaObject, Qt, Q_ARG, QThread


class ReminderThread(threading.Thread):
    def __init__(self, db_session_func, user_id, parent_window):
        super().__init__(daemon=True)
        # 使用弱引用
        self.get_db = db_session_func
        self.user_id = user_id
        self.parent_window = parent_window
        self._running = True
        self.last_checked_time = datetime.min  # 上次检查时间

    # 修改数据库会话获取逻辑
    @contextmanager
    def _get_db_session(self):
        db = None
        try:
            db = next(self.get_db())
            if db is None:
                raise RuntimeError("数据库连接失败")
            yield db
            db.commit()
        except StopIteration:
            raise RuntimeError("无法获取数据库会话")
        except Exception as e:
            logging.error(f"数据库错误: {str(e)}")
            if db: db.rollback()
            raise
        finally:
            if db: db.close()

    def run(self):
        while self._running:
            try:
                with self._get_db_session() as db:
                    current_time = datetime.now()
                    schedules = self._get_active_reminders(db, current_time)

                    # 所有操作在会话内完成
                    for schedule_dict in schedules:
                        if self._should_trigger(schedule_dict, current_time):  # 传入db
                            self._trigger_reminder(schedule_dict)
                self.last_checked_time = current_time
            except Exception as e:
                logging.error(f"提醒服务异常: {str(e)}", exc_info=True)
            finally:
                time.sleep(15)  #15s检查一次

    def _get_active_reminders(self, db, current_time):
        """安全触发提醒"""
        try:
            time_window = timedelta(minutes=1)
            reminders = db.query(Schedule).options(
                load_only(
                    Schedule.id,
                    Schedule.reminder_at,
                    Schedule.title,
                    Schedule.notes,
                    Schedule.start_time,
                    Schedule.end_time
                )
            ).filter(
                Schedule.user_id == self.user_id,
                Schedule.reminder_at != None,
                Schedule.reminder_at.between(
                    current_time - time_window,
                    current_time + time_window
                )
            ).all()

            # 转换为dict，避免数据库会话生命周期的问题
            return[
                {
                    'id': s.id,
                    'reminder_at': s.reminder_at,
                    'title': s.title,
                    'notes': s.notes,
                    'start_time': s.start_time,
                    'end_time': s.end_time
                }
                for s in reminders
            ]  # 确保返回可迭代对象
        except Exception as e:
            logging.error(f"查询失败: {str(e)}")
            db.rollback()
            return []

    def _should_trigger(self, schedule_dict, current_time):
        """字典判断是否触发提醒"""
        reminder_time = schedule_dict["reminder_at"].replace(second=0, microsecond=0)
        check_time = current_time.replace(second=0, microsecond=0)
        return reminder_time == check_time

    def _trigger_reminder(self, schedule_dict):
        # 清空提醒时间,避免重复提醒
        try:
            with self._get_db_session() as db:
                db.query(Schedule).filter(Schedule.id == schedule_dict["id"]).update({"reminder_at": None})
                db.commit()
        except Exception as e:
            logging.error(f"清除提醒时间失败: {str(e)}", exc_info=True)

        #在主线程显示弹窗
        try:
            if not self.parent_window:
                raise RuntimeError("父窗口对象已销毁")

            if QThread.currentThread() != self.parent_window.thread():
                QMetaObject.invokeMethod(
                    self.parent_window,
                    '_show_reminder_dialog',
                    Qt.QueuedConnection,
                    Q_ARG(object, schedule_dict)
                )
            else:
                self.parent_window._show_reminder_dialog(schedule_dict)

        except Exception as e:
            logging.error(f"触发提醒失败: {str(e)}", exc_info=True)

    def stop(self):
        self._running = False